<?php


namespace app\common\service\store;


use app\admin\model\order\Order;
use app\admin\model\store\Goods;
use app\admin\model\store\GoodsSku;
use app\admin\model\store\Seckill;
use app\admin\model\store\SeckillConfig;
use app\common\service\BaseService;
use app\common\service\lib\DelayQueue;
use app\common\service\lib\RabbitMQ;
use app\common\service\OrderService;
use app\Request;
use PhpAmqpLib\Message\AMQPMessage;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;

class SeckillService extends BaseService
{
    /**
     * Author:YangXinPeng
     * 下拉选择秒杀商品
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function goods()
    {
        $data = GoodsSku::with('goods')->select();
        $data && $data = $data->toArray();
        $arr = [];
        foreach ($data as $key => $value) {
            $arr[$key]['id'] = $value['id'];
            $attr = json_decode($value['attr_values'], true);
            $json = implode("/", $attr);
            $arr[$key]['goods_name'] = $value['goods_name'] . "/" . $json;
        }
        return ['code' => 1, 'msg' => null, 'data' => $arr];
    }

    /**
     * Author:YangXinPeng
     * 下拉选择秒杀配置
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function seckillConfigs()
    {
        $data = SeckillConfig::field('id,title')->select();
        $data && $data = $data->toArray();
        return $data;
    }

    /**
     * Author:YangXinPeng
     * ID查询商品
     * @param $id
     * @return array|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function good($id)
    {
        $data = GoodsSku::find($id);
        $data && $data = $data->toArray();
        return $data;
    }

    /**
     * Author:YangXinPeng
     * 秒杀前置准备工作
     * @param $seckillId
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function initSeckill($seckillId)
    {
        $info = Seckill::find($seckillId);
        $info && $info->toArray();
        $keyUser = config('setting.seckill.userQualification') . ":" . $info['config_id'] . ":" . $info['goods_id'];
        $keyGoods = config('setting.seckill.seckillInventory') . ":" . $info['config_id'] . ":" . $info['goods_id'];
        $redis = Cache::store('redis');
        $redis->select(2);
        if ($redis->llen($keyGoods) == 0 && $redis->llen($keyUser) == 0) {
            for ($i = 0; $i < $info['limit']; $i++) {
                $redis->lpush($keyGoods, 1);
            }
        }
    }

    /**
     * Author:YangXinPeng
     * 秒杀逻辑
     * @param $seckillId
     * @param $uid
     * @param $goodsId
     * @param $params
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function seckill($configId, $uid, $goodsId)
    {
//        $where['start_time'] = array("gt", time());
//        $where['end_time'] = array("lt", time());
//        $where['id'] = $configId;
//        $config = SeckillConfig::where($where)->find();
//        if (!$config) {
//            return self::fail('秒杀结束');
//        }
        $keyUser = config('setting.seckill.userQualification') . ":" . $configId . ":" . $goodsId;
        $keyGoods = config('setting.seckill.seckillInventory') . ":" . $configId . ":" . $goodsId;
        $redis = Cache::store('redis');
        $redis->select(2);
        $arr = $redis->lrange($keyUser, 0, -1);
        if (in_array($uid, $arr)) {
            return self::fail('您已经在秒杀中，请勿重复操作');
        }
        $num = $redis->rpop($keyGoods);
        if ($num == 1) {
            $redis->lpush($keyUser, $uid);
            return self::success('秒杀成功');
        } else {
            return self::fail('秒杀失败');
        }
    }

    /**
     * Author:YangXinPeng
     * 秒杀订单延时队列生产者
     * @param $orderId
     * @param $goodsId
     */
    public static function queOrder($orderId, $goodsId)
    {
        $delay = new DelayQueue();
        $ttl = 1000 * 60 * 5;//订单5m后超时
        $delayExName = 'delay-order-exchange';//超时exchange
        $delayQueueName = 'delay-order-queue';//超时queue
        $queueName = 'ttl-order-queue';//订单queue
        $delay->createQueue($ttl, $delayExName, $delayQueueName, $queueName);
        $data = [
            'order_no' => $orderId,
            'sku_id' => $goodsId
        ];
        $delay->sendMessage(json_encode($data), $queueName);
        sleep(1);
    }

    /**
     * Author:YangXinPeng
     * 秒杀订单延时队列消费者
     * @throws \ErrorException
     */
    public static function consumeOrder()
    {
        $redis = Cache::store('redis');
        $redis->select(2);
        $delay = new DelayQueue();
        $delayQueueName = 'delay-order-queue';
        $callback = function ($msg) use ($redis) {
            $val = json_decode($msg->body, true);
            $orderId = $val['order_no'];
            $goodsId = $val['sku_id'];
            $goodId = GoodsSku::where('id', $goodsId)->value('goods_id');
            $paid = Order::where('order_no', $orderId)->value('pay_status');
            $uid = Order::where('order_no', $orderId)->value('uid');
            $seckillId = Order::where('order_no', $orderId)->value('seckill_id');
            $keyUser = config('setting.seckill.userQualification') . ":" . $seckillId . ":" . $goodsId;
            $keyGoods = config('setting.seckill.seckillInventory') . ":" . $seckillId . ":" . $goodsId;
            //处理秒杀订单超时逻辑
            if ($paid === 0) {
                $redis->lrem($keyUser, 1, $uid);
                $redis->lpush($keyGoods, 1);
                Db::startTrans();
                try {
                    GoodsSku::where('id', $goodsId)->inc('sku_stock')->update();
                    Goods::where('id', $goodId)->inc('goods_stock')->update();
                    Db::commit();
                } catch (\Exception $e) {
                    Db::rollback();
                    Log::info('秒杀延时处理错误');
                }
            }
            $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
            sleep(1);
        };
        /**
         * 消费已经超时的订单信息，进行处理
         */
        $delay->consumeMessage($delayQueueName, $callback);
    }


    /**
     * Author:YangXinPeng
     * 秒杀前台展示
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function show()
    {
        $data = Seckill::select();
        $data && $data = $data->toArray();
        foreach ($data as $key=>$value) {
            $time = $value['period_time'];
            $arr = explode("-", $time);
            $start_time = substr($arr[2],strpos($arr[2],'T')+1);
            $end_time =substr($arr[5],strpos($arr[5],'T')+1);
            $data[$key]['start_time'] = $start_time;
            $data[$key]['end_time'] = $end_time;
        }
        return self::success('成功',$data);
    }

    public static function seckillList($where)
    {
        if (empty($where)){
            return self::fail('参数错误');
        }
        $data = SeckillConfig::where($where)->with(['seckillList','seckillList.goodsList'])->select();
        $data && $data = $data->toArray();

        return self::success('获取成功',$data);
    }


}